#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gpio.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/uaccess.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include "mvdef.h"
/* 定义步进电机的GPIO引脚 */
#define MOTOR_PIN_1 68
#define MOTOR_PIN_2 58
#define MOTOR_PIN_3 26
#define MOTOR_PIN_4 27
/* 定义ioctl命令 */
#define MOTOR_START _IO('M', 0)
#define MOTOR_STOP  _IO('M', 1)
#define SET_SPEED_LOW _IO('M', 2)
#define SET_SPEED_HIGH _IO('M', 3)
#define SET_DIRECTION _IO('M', 4)
/* 定义电机的步序 */
static mv_cs32_t _gcs32_step_sequence[8][4] = {
    {1, 0, 0, 0},
    {1, 1, 0, 0},
    {0, 1, 0, 0},
    {0, 1, 1, 0},
    {0, 0, 1, 0},
    {0, 0, 1, 1},
    {0, 0, 0, 1},
    {1, 0, 0, 1}
};
/* 当前步序索引 */
static mv_s32_t _step_index = 0;
/* 定时器结构 */
static struct timer_list _motor_timer;
/* 设备号 */
static dev_t _devt;
/* 字符设备结构 */
static struct cdev _cdev;
/* 设备类 */
static struct class *class;
/* 设备 */
static struct device *device;
/* 电机速度 */
static mv_s32_t _gs32_motor_speed = 10;
/* 电机方向 */
static mv_s32_t _gs32_direction = 1;

/**
 * @brief   步进电机定时步进函数
 * @param   t [IN] 定时器指针，指向struct timer_list结构体
 * @return  无返回值
 * @note    该函数由内核定时器周期性调用，实现步进电机的步进控制。每次调用会按照当前步序设置GPIO引脚电平，并根据方向更新步序索引，最后重新启动定时器以实现持续步进。
 */
static mv_void_t motor_step(struct timer_list *t)
{
    /* 设置GPIO引脚的电平 */
    gpio_set_value(MOTOR_PIN_1, _gcs32_step_sequence[_step_index][0]);
    gpio_set_value(MOTOR_PIN_2, _gcs32_step_sequence[_step_index][1]);
    gpio_set_value(MOTOR_PIN_3, _gcs32_step_sequence[_step_index][2]);
    gpio_set_value(MOTOR_PIN_4, _gcs32_step_sequence[_step_index][3]);
    /* 更新步序索引 */
    _step_index = (_step_index + _gs32_direction + 8) % 8;
    /* 重新启动定时器 */
    mod_timer(&_motor_timer, jiffies + msecs_to_jiffies(_gs32_motor_speed));
}

/**
 * @brief   ioctl命令处理函数
 * @param   filp    [IN] 文件指针，指向打开的设备文件
 * @param   u32_cmd [IN] ioctl命令字
 * @param   u32_arg [IN] 命令参数（本驱动未使用）
 * @return  MV_EC_SUCCESS      操作成功
 *          MV_EC_INVALID_ARGS 无效命令参数
 * @note    该函数根据用户空间传入的ioctl命令，控制电机启动、停止、调速及方向切换。部分命令会重启定时器以立即生效。
 */
static mv_s32_t motor_ioctl(struct file *filp, mv_u32_t u32_cmd, mv_u32_t u32_arg)
{
    mv_s32_t _s32_ret = MV_EC_SUCCESS;

    switch (u32_cmd) {
        case MOTOR_START:
            mod_timer(&_motor_timer, jiffies + msecs_to_jiffies(_gs32_motor_speed));
            break;
        case MOTOR_STOP:
            /* 删除定时器 */
            del_timer(&_motor_timer);
            /* 所有引脚置低 */
            gpio_set_value(MOTOR_PIN_1, 0);
            gpio_set_value(MOTOR_PIN_2, 0);
            gpio_set_value(MOTOR_PIN_3, 0);
            gpio_set_value(MOTOR_PIN_4, 0);
            break;
        case SET_SPEED_LOW:
            _gs32_motor_speed = 15;
            mod_timer(&_motor_timer, jiffies + msecs_to_jiffies(_gs32_motor_speed));
            break;
        case SET_SPEED_HIGH:
            _gs32_motor_speed = 1;
            mod_timer(&_motor_timer, jiffies + msecs_to_jiffies(_gs32_motor_speed));
            break;
        case SET_DIRECTION:
            _gs32_direction = (_gs32_direction == 1) ? -1 : 1;
            break;
        default:
            _s32_ret = MV_EC_INVALID_ARGS;
    }
    return _s32_ret;
}

/**
 * @brief   文件操作结构体
 * @note    该结构体定义了字符设备的操作方法，包括ioctl命令处理函数。
 */
static struct file_operations _fops = {
    .owner = THIS_MODULE,
    .unlocked_ioctl = motor_ioctl,
    .compat_ioctl = motor_ioctl,
};

/**
 * @brief   模块加载函数
 * @param   无参数
 * @return  MV_EC_SUCCESS      操作成功
 *          MV_EC_FAILED       操作失败
 * @note    该函数用于初始化字符设备，包括分配设备号、初始化cdev、创建类和设备，并注册GPIO引脚。
 */
static mv_s32_t __init _motor_driver_init(mv_void_t)
{
    mv_s32_t _s32_ret;

    /* 分配设备号 */
    _s32_ret = alloc_chrdev_region(&_devt, 0, 1, "motor_driver");
    if (_s32_ret < 0) {
        printk(KERN_ERR "Failed to allocate char device region\n");
        return MV_EC_FAILED;
    }

    /* 初始化cdev */
    cdev_init(&_cdev, &_fops);
    _cdev.owner = THIS_MODULE;
    _s32_ret = cdev_add(&_cdev, _devt, 1);
    if (_s32_ret < 0) {
        printk(KERN_ERR "Failed to add char device\n");
        unregister_chrdev_region(_devt, 1);
        return MV_EC_FAILED;
    }

    /* 创建类 */
    class = class_create(THIS_MODULE, "motor_class");
    if (IS_ERR(class)) {
        printk(KERN_ERR "Failed to create device class\n");
        cdev_del(&_cdev);
        unregister_chrdev_region(_devt, 1);
        return MV_EC_FAILED;
    }

    /* 创建设备 */
    device = device_create(class, NULL, _devt, NULL, "motor_device");
    if (IS_ERR(device)) {
        printk(KERN_ERR "Failed to create device\n");
        class_destroy(class);
        cdev_del(&_cdev);
        unregister_chrdev_region(_devt, 1);
        return MV_EC_FAILED;
    }

    /* 注册GPIO引脚 */
    _s32_ret = gpio_request(MOTOR_PIN_1, "motor_pin_1");
    if (_s32_ret) {
        printk(KERN_ERR "Failed to request GPIO pin %d\n", MOTOR_PIN_1);
        goto err_free_device;
    }

    _s32_ret = gpio_request(MOTOR_PIN_2, "motor_pin_2");
    if (_s32_ret) {
        printk(KERN_ERR "Failed to request GPIO pin %d\n", MOTOR_PIN_2);
        gpio_free(MOTOR_PIN_1);
        goto err_free_device;
    }

    _s32_ret = gpio_request(MOTOR_PIN_3, "motor_pin_3");
    if (_s32_ret) {
        printk(KERN_ERR "Failed to request GPIO pin %d\n", MOTOR_PIN_3);
        gpio_free(MOTOR_PIN_1);
        gpio_free(MOTOR_PIN_2);
        goto err_free_device;
    }

    _s32_ret = gpio_request(MOTOR_PIN_4, "motor_pin_4");
    if (_s32_ret) {
        printk(KERN_ERR "Failed to request GPIO pin %d\n", MOTOR_PIN_4);
        gpio_free(MOTOR_PIN_1);
        gpio_free(MOTOR_PIN_2);
        gpio_free(MOTOR_PIN_3);
        goto err_free_device;
    }

    /* 设置GPIO引脚为输出模式 */
    gpio_direction_output(MOTOR_PIN_1, 0);
    gpio_direction_output(MOTOR_PIN_2, 0);
    gpio_direction_output(MOTOR_PIN_3, 0);
    gpio_direction_output(MOTOR_PIN_4, 0);

    /* 初始化定时器 */
    #ifdef CONFIG_TIMER_SETUP
    timer_setup(&_motor_timer, motor_step, 0);
    #else
    init_timer(&_motor_timer);
    _motor_timer.function = motor_step;
    _motor_timer.data = 0;
    #endif

    printk(KERN_INFO "Step motor driver loaded.\n");
    return MV_EC_SUCCESS;

    /* 错误处理 */
err_free_device:
    device_destroy(class, _devt);
    class_destroy(class);
    cdev_del(&_cdev);
    unregister_chrdev_region(_devt, 1);
    return MV_EC_FAILED;
}

/**
 * @brief   模块卸载函数
 * @param   无参数
 * @return  无返回值
 * @note    该函数用于卸载字符设备，包括删除定时器、释放GPIO引脚、销毁设备、删除cdev和释放设备号。
 */
static mv_void_t __exit _motor_driver_exit(mv_void_t)
{
    /* 删除定时器 */
    del_timer(&_motor_timer);
    /* 释放GPIO引脚 */
    gpio_free(MOTOR_PIN_1);
    gpio_free(MOTOR_PIN_2);
    gpio_free(MOTOR_PIN_3);
    gpio_free(MOTOR_PIN_4);
    /* 销毁设备 */
    device_destroy(class, _devt);
    class_destroy(class);
    /* 删除cdev */
    cdev_del(&_cdev);
    /* 释放设备号 */
    unregister_chrdev_region(_devt, 1);
    printk(KERN_INFO "Step motor driver unloaded.\n");
}

/* 模块加载和卸载 */
module_init(_motor_driver_init);
module_exit(_motor_driver_exit);

/* 模块信息 */
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Your Name");
MODULE_DESCRIPTION("A simple step motor driver for Linux kernel with ioctl support");
MODULE_VERSION("0.1");